package com.imooc.bilibili.service;

import com.alibaba.fastjson.JSONArray;
import com.imooc.bilibili.dao.VideoDao;
import com.imooc.bilibili.domain.*;
import com.imooc.bilibili.exception.ConditionException;
import com.imooc.bilibili.util.FastDFSUtil;
import com.imooc.bilibili.util.IpUtil;
import eu.bitwalker.useragentutils.UserAgent;
import net.bytebuddy.build.Plugin;
import org.omg.CORBA.COMM_FAILURE;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class VideoService {

    @Autowired
    private VideoDao videoDao;
    @Autowired
    private UserService userService;

    @Autowired
    private UserCoinService userCoinService;

    @Autowired
    private FastDFSUtil fastDFSUtil;

    /**
     * 添加视频投稿
     * @param video
     * @return
     */
    @Transactional
    public void addVideos(Video video) {
        Date now = new Date();
        video.setCreateTime(now);
        videoDao.addVideos(video);
        Long videoId = video.getId();
        List<VideoTag> videoTagList = video.getVideoTagList();
        if (videoTagList != null) {
            videoTagList.forEach(videoTag -> {
                videoTag.setCreateTime(now);
                videoTag.setVideoId(videoId);
            });
            videoDao.batchAddVideoTags(videoTagList);
        }
    }

    /**
     * 视频分区分页查询
     * @param size
     * @param no
     * @param area
     * @return
     */
    public PageResult<Video> pageListVideos(Integer size, Integer no, String area) {
        if(size == null || no == null){
            throw new ConditionException("参数异常！");
        }
        Map<String,Object> params = new HashMap<>();
        params.put("start",(no-1)*size);
        params.put("limit",size);
        params.put("area",area);
        List<Video> list = new ArrayList<>();
        Integer total = videoDao.pageCountVideos(params);
        if (total != null) {
            list = videoDao.pageListVideos(params);
        }
        return new PageResult<>(total,list);
    }

    /**
     * 视频在线观看
     * @param request
     * @param response
     * @param path
     * @throws Exception
     */
    public void viewVideoOnlineBySlices(HttpServletRequest request,
                                        HttpServletResponse response,
                                        String path) throws Exception {
        fastDFSUtil.viewVideoOnlineBySlices(request,response,path);
    }

    /**
     * 视频点赞
     * @param userId
     * @param videoId
     */
    public void addVideoLike(Long userId, Long videoId) {
        Video video = videoDao.getVideoById(videoId);
        if (video == null){
            throw new ConditionException("非法视频！");
        }
        VideoLike videoLike = videoDao.getVideoLikeByUserIdAndVideoId(userId,videoId);
        if (videoLike != null) {
            throw  new ConditionException("已经赞过！");
        }
        videoLike = new VideoLike();
        videoLike.setUserId(userId);
        videoLike.setVideoId(videoId);
        videoLike.setCreateTime(new Date());
        videoDao.addVideoLike(videoLike);
    }

    /**
     * 取消点赞
     * @param userId
     * @param videoId
     */
    public void deleteVideoLike(Long userId, Long videoId) {
        videoDao.deleteVideoLike(userId,videoId);
    }

    /**
     * 查询视频点赞数量
     * @param videoId
     * @return
     */
    public Map<String, Object> getVideoLikes(Long userId, Long videoId) {
        Long count = videoDao.getCountVideoLikes(videoId);

        VideoLike videoLike = videoDao.getVideoLikeByUserIdAndVideoId(userId, videoId);
        Boolean flag = videoLike != null;
        Map<String,Object> result = new HashMap<>();
        result.put("count",count);
        result.put("flag",flag);
        return result;
    }

    /**
     * 视频收藏
     * @param videoCollection
     * @param userId
     */
    @Transactional
    public void addVideoCollection(VideoCollection videoCollection, Long userId) {
        Long videoId = videoCollection.getVideoId();
        Long groupId = videoCollection.getGroupId();
        if (videoId == null || groupId == null){
            throw new ConditionException("参数异常！");
        }
        Video video = videoDao.getVideoById(videoId);
        if (video == null) {
            throw new ConditionException("非法视频！");
        }
        // 删除原有的视频收藏
        videoDao.deleteVideoCollection(userId,videoId);
        // 添加新的视频收藏
        videoCollection.setUserId(userId);
        videoCollection.setCreateTime(new Date());
        videoDao.addVideoCollection(videoCollection);
    }


    /**
     * 取消收藏
     * @param videoId
     * @param userId
     */
    public void deleteVideoCollection(Long videoId, Long userId) {
        videoDao.deleteVideoCollection(userId,videoId);
    }

    /**
     * 获取视频的收藏数量
     * @param videoId
     * @param userId
     * @return
     */
    public Map<String, Object> getVideoCollections(Long videoId, Long userId) {
        Long count = videoDao.getCountVideoCollection(videoId);
        VideoCollection videoCollection = videoDao.getVideoCollectionByUserIdAndVideoId(videoId,userId);
        Boolean flag = videoCollection != null;
        Map<String, Object> result = new HashMap<>();
        result.put("count",count);
        result.put("flag",flag);
        return result;
    }

    /**
     * 视频投币
     * @param videoCoin
     * @param userId
     */
    @Transactional
    public void addVideoCoins(VideoCoin videoCoin, Long userId) {
        Long videoId = videoCoin.getVideoId();
        Integer amount = videoCoin.getAmount();
        if (videoId == null || amount == null){
            throw new ConditionException("参数异常!");
        }
        Video video = videoDao.getVideoById(videoId);
        if (video == null) {
            throw new ConditionException("非法视频！");
        }
        // 查询该用户的硬币数量
        Long userCoinAmount = userCoinService.getAmountByUserId(userId);
        userCoinAmount = userCoinAmount == null ? 0 : userCoinAmount;
        if (userCoinAmount < amount){
            throw new ConditionException("硬币数量不足！");
        }
        // 查询该用户已经对此视频投了多少币
        VideoCoin dbVideoCoin = videoDao.getVideoCoinByUserIdAndVideoId(videoId,userId);
        if (dbVideoCoin == null){
            // 新增用户投币
            videoCoin.setUserId(userId);
            videoCoin.setCreateTime(new Date());
            videoDao.addVideoCoins(videoCoin);
        }else {
            // 新增用户投币
            Integer dbAmount = dbVideoCoin.getAmount();
            dbAmount += amount;
            videoCoin.setAmount(dbAmount);
            videoCoin.setUserId(userId);
            videoCoin.setCreateTime(new Date());
            videoDao.updateVideoCoin(videoCoin);
        }
        // 更新用户硬币总数
        userCoinService.updateUserCoinAmount(userId,(userCoinAmount - amount));
    }

    /**
     * 查询视频投币总数
     * @param videoId
     * @param userId
     * @return
     */
    public Map<String, Object> getVideoCoins(Long videoId, Long userId) {
        Integer amount = videoDao.getVideoCoins(videoId);
        VideoCoin videoCoin = videoDao.getVideoCoinByUserIdAndVideoId(videoId, userId);
        Boolean flag = videoCoin != null;
        Map<String,Object> result = new HashMap<>();
        result.put("amount",amount);
        result.put("flag",flag);
        return result;
    }

    /**
     * 添加视频评论
     * @param videoComment
     * @param userId
     */
    public void addVideoComment(VideoComment videoComment, Long userId) {
        Long videoId = videoComment.getVideoId();
        if (videoId == null){
            throw new ConditionException("参数错误！");
        }
        Video video = videoDao.getVideoById(videoId);
        if (video == null){
            throw new ConditionException("非法视频！");
        }
        videoComment.setUserId(userId);
        videoComment.setCreateTime(new Date());
        videoDao.addVideoComment(videoComment);
    }

    /**
     * 视频评论分页查询
     * @param size
     * @param no
     * @param videoId
     * @return
     */
    public PageResult<VideoComment> pageListVideoComments( Integer size,
                                                           Integer no,
                                                           Long videoId) {
        Video video = videoDao.getVideoById(videoId);
        if (video == null) {
            throw new ConditionException("非法视频！");
        }
        Map<String,Object> params = new HashMap<>();
        params.put("startIndex",(no-1)*size);
        params.put("size",size);
        params.put("videoId",videoId);
        Integer total = videoDao.getCountVideoComments(params);
        List<VideoComment> parentCommentList = new ArrayList<>();
        if (total > 0){
            // 获取一级评论list集合
            parentCommentList = videoDao.pageListVideoComments(params);
            // 将一级评论id抽取出来
            Set<Long> parentIdSet = parentCommentList.stream().map(VideoComment::getId).collect(Collectors.toSet());
            // 获取二级评论list集合
            List<VideoComment> childCommentList = videoDao.batchGetVideoCommentsByRootId(parentIdSet);
            // 获取一级、二级评论的用户id
            Set<Long> parentUserIdSet = parentCommentList.stream().map(VideoComment::getUserId).collect(Collectors.toSet());
            Set<Long> childUserIdSet = childCommentList.stream().map(VideoComment::getUserId).collect(Collectors.toSet());
            Set<Long> childReplyIdSet = childCommentList.stream().map(VideoComment::getReplyUserId).collect(Collectors.toSet());
            parentUserIdSet.addAll(childUserIdSet);
            parentUserIdSet.addAll(childReplyIdSet);

            List<Integer> integerList = JSONArray.parseArray(parentUserIdSet.toString(), Integer.class);
            Set<Integer> pus = integerList.stream().collect(Collectors.toSet());
            // 获取评论视频的用户信息
            List<UserInfo> userInfoList = userService.getUserInfoByUserIds(pus);
            Map<Long, UserInfo> userInfoMap = userInfoList.stream().collect(Collectors.toMap(UserInfo::getUserId, UserInfo -> UserInfo));
            parentCommentList.forEach(parentComment ->{
                Long id = parentComment.getId();
                List<VideoComment> childList = new ArrayList<>();
                childCommentList.forEach(childComment ->{
                    if (id.equals(childComment.getRootId())){
                        childComment.setUserInfo(userInfoMap.get(childComment.getUserId()));
                        childComment.setReplyUserInfo(userInfoMap.get(childComment.getReplyUserId()));
                    }
                    childList.add(childComment);
                });
                parentComment.setChildList(childList);
                parentComment.setUserInfo(userInfoMap.get(parentComment.getUserId()));
            });
        }

        return new PageResult<>(total,parentCommentList);
    }

    /**
     * 获取视频详情
     * @param videoId
     * @return
     */
    public Map<String, Object> getVideoDetails(Long videoId) {
        Video video = videoDao.getVideoById(videoId);
        if (video == null) {
           throw new ConditionException("非法视频！");
        }
        Long userId = video.getUserId();
        User userInfo = userService.getUserInfo(userId);
        Map<String,Object> result = new HashMap<>();
        result.put("video",video);
        result.put("userInfo",userInfo);
        return result;
    }

    /**
     * 添加视频观看记录
     * @param videoView
     * @param request
     * @return
     */
    public void addVideoView(VideoView videoView, HttpServletRequest request) {
        Long userId = videoView.getUserId();
        Long videoId = videoView.getVideoId();
        // 生成clientId
        String agent = request.getHeader("User-Agent");
        UserAgent userAgent = UserAgent.parseUserAgentString(agent);
        String clientId = String.valueOf(userAgent.getId());
        // 获取IP
        String ip = IpUtil.getIP(request);
        Map<String,Object> params = new HashMap<>();
        if (userId != null){
            params.put("userId",userId);
        }else {
            params.put("clientId",clientId);
            params.put("ip",ip);
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String today = sdf.format(new Date());
        params.put("today",today);
        params.put("videoId",videoId);
        VideoView dbVideoView = videoDao.getVideoViews(params);
        if (dbVideoView == null){
            videoView.setClientId(clientId);
            videoView.setIp(ip);
            videoView.setCreateTime(new Date());
            videoDao.addVideoView(videoView);
        }
    }

    /**
     * 查询视频观看次数
     * @param videoId
     * @return
     */
    public Integer getVideoViewCounts(Long videoId) {
        return videoDao.getVideoViewCounts(videoId);
    }
}
